package com.yichi.manager;

import androidx.annotation.NonNull;

import com.yichi.global.AppConfig;
import com.yichi.service.DeviceService;
import com.yichi.util.JsonUtil;
import com.yichi.util.StringUtil;

import java.io.IOException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * HTTP请求管理类
 *
 * @use HttpManager.getInstance().get(...)
 * HttpManager.getInstance().post(...)
 * 在回调方法onHttpRequestSuccess和onHttpRequestError处理HTTP请求结果
 */
public class HttpManager {
    private static final String TAG = "HttpManager";
    public static final MediaType TYPE_JSON = MediaType.parse("application/json; charset=utf-8");

    private OkHttpClient okHttpClient;

    private HttpManager() {
    }

    private static HttpManager instance;// 单例

    public static HttpManager getInstance() {
        if (instance == null) {
            synchronized (HttpManager.class) {
                if (instance == null) {
                    instance = new HttpManager();
                }
            }
        }
        return instance;
    }

    /**
     * GET请求
     */
    public String get(final String url, Map<String, Object> queryParams) throws Exception {
        OkHttpClient client = getHttpClient();
        if (client == null) {
            throw new Exception(TAG + "OkHttpClient获取失败");
        }

        StringBuffer sb = new StringBuffer();
        sb.append(url);

        Set<Map.Entry<String, Object>> set = queryParams == null ? null : queryParams.entrySet();
        if (set != null) {
            boolean isFirst = true;
            for (Map.Entry<String, Object> entry : set) {
                sb.append(isFirst ? "?" : "&");
                sb.append(StringUtil.trim(entry.getKey()));
                sb.append("=");
                sb.append(StringUtil.trim(entry.getValue()));

                isFirst = false;
            }
        }

        return getResponseJson(client, new Request.Builder().url(sb.toString()).build());
    }

    /**
     * GET请求
     */
    public String get(final String url) throws Exception {
        OkHttpClient client = getHttpClient();
        if (client == null) {
            throw new Exception(TAG + "OkHttpClient获取失败");
        }

        return getResponseJson(client, new Request.Builder().url(url).build());
    }

    /**
     * GET请求
     */
    public void getAsync(final String url, final Map<String, Object> queryParams,
                         final OnHttpResponseListener listener) throws Exception {

        OkHttpClient client = getHttpClient();
        if (client == null) {
            throw new Exception(TAG + "OkHttpClient获取失败");
        }

        StringBuffer sb = new StringBuffer();
        sb.append(url);

        Set<Map.Entry<String, Object>> set = queryParams == null ? null : queryParams.entrySet();
        if (set != null) {
            boolean isFirst = true;
            for (Map.Entry<String, Object> entry : set) {
                sb.append(isFirst ? "?" : "&");
                sb.append(StringUtil.trim(entry.getKey()));
                sb.append("=");
                sb.append(StringUtil.trim(entry.getValue()));

                isFirst = false;
            }
        }

        Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(sb.toString()).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                listener.failed(call, e);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                listener.success(call, response);
            }
        });
    }

    /**
     * POST请求
     */
    public String post(final String url, Map<String, Object> bodyParams, final boolean isJson) throws Exception {
        OkHttpClient client = getHttpClient();
        if (client == null) {
            throw new Exception(TAG + "OkHttpClient获取失败");
        }

        RequestBody requestBody;
        if (isJson) {
            String body = JsonUtil.toJSONString(bodyParams);
            requestBody = RequestBody.Companion.create(body, TYPE_JSON);
        } else {
            FormBody.Builder builder = new FormBody.Builder();
            Set<Map.Entry<String, Object>> set = bodyParams == null ? null : bodyParams.entrySet();
            if (set != null) {
                for (Map.Entry<String, Object> entry : set) {
                    builder.add(StringUtil.trim(entry.getKey()), StringUtil.trim(entry.getValue()));
                }
            }

            requestBody = builder.build();
        }

        return getResponseJson(client, new Request.Builder().url(url).post(requestBody).build());
    }

    public String postJson(final String url, Map<String, Object> bodyParams) throws Exception {
        return post(url, bodyParams, true);
    }

    public String postForm(final String url, Map<String, Object> bodyParams) throws Exception {
        return post(url, bodyParams, false);
    }

    /**
     * POST请求异步
     */
    public void postJsonAsync(final String url, Map<String, Object> bodyParams, final OnHttpResponseListener listener) throws Exception {
        OkHttpClient client = getHttpClient();
        if (client == null) {
            throw new Exception(TAG + "OkHttpClient获取失败");
        }

        RequestBody requestBody;
        String body = JsonUtil.toJSONString(bodyParams);
        requestBody = RequestBody.Companion.create(body, TYPE_JSON);

        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(requestBody).url(url).build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                listener.failed(call, e);
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                listener.success(call, response);
            }
        });
    }

    private OkHttpClient getHttpClient() throws Exception {
        if (okHttpClient != null) {
            return okHttpClient;
        }

        TrustManager[] trustManagers = new TrustManager[]{new TrustAllCerts()};

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagers, new SecureRandom());

        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        //读取超时
        clientBuilder.readTimeout(100, TimeUnit.SECONDS);
        //连接超时
        clientBuilder.connectTimeout(60, TimeUnit.SECONDS);
        //写入超时
        clientBuilder.writeTimeout(60, TimeUnit.SECONDS);
        //支持HTTPS请求，跳过证书验证
        clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0]);
        clientBuilder.hostnameVerifier((hostname, session) -> true);
        //添加拦截器
        clientBuilder.addInterceptor(new TokenHeaderInterceptor());
        return okHttpClient = clientBuilder.build();
    }

    /**
     * @param client
     * @param request
     * @return
     * @throws Exception
     */
    private String getResponseJson(OkHttpClient client, Request request) throws Exception {
        if (client == null || request == null) {
            throw new Exception("OkHttpClient为null");
        }
        Response response = client.newCall(request).execute();
        return response.isSuccessful() ? response.body().string() : null;
    }

    /**
     * 用于信任所有证书
     */
    class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    class TokenHeaderInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();
            String token = AppConfig.platFormToken;//可以从utils中获取
            if (StringUtil.isEmpty(token)) {
                //走旧请求
                return chain.proceed(originalRequest);
            } else {
                //走新请求
                Request newRequest = originalRequest.newBuilder()
                        .header("token", token)
                        .build();
                Response response = chain.proceed(newRequest);
                return response;
            }
        }

    }
}
